package we.dispatcher;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.util.concurrent.BlockingQueue;
import we.common.CCommonHandler;
import we.config.CConfigHandler;
import we.config.CConstant;

public class CWriteHandler implements Runnable {

    private BlockingQueue<CMessage> out;
    private ByteBuffer policyData;
    private long timeout;
    private Charset charset;
    private CharsetEncoder encoder;

    public CWriteHandler(BlockingQueue<CMessage> out) {
        this.out = out;
        timeout = CConfigHandler.instance().getLong("write.timeout");
        charset = Charset.forName(CConstant.DEFAULT_ENCODING);
        encoder = charset.newEncoder();
        initPolicyData();
    }

    @Override
    public void run() {
        while (true) {
            try {
                CMessage obj = out.take();
                ByteBuffer bb;
                if (obj.policyResponse) {
                    bb = policyData.duplicate();
                } else {
                    bb = encoder.encode(CharBuffer.wrap(obj.data));
                }

                while (bb.hasRemaining()) {
                    int byteWrite = obj.channel.write(bb);
                    if (byteWrite == 0) {
                        Selector writeSelector = Selector.open();
                        obj.channel.register(writeSelector,
                                SelectionKey.OP_WRITE);
                        int code = writeSelector.select(timeout);

                        if (code == 1) {
                            obj.channel.write(bb);
                        } else {
                            System.out.println("Failure write to client");
                            break;
                        }
                    }
                }
            } catch (InterruptedException e) {
                CCommonHandler.writeErrLog(e);
            } catch (IOException e) {
                CCommonHandler.writeErrLog(e);
                // TODO
            }
        }
    }

    private void initPolicyData() {
        try {
            StringBuilder xml = new StringBuilder(1024);
            xml.append("<?xml version=\"1.0\"?><cross-domain-policy>");
            String temp = CConfigHandler.instance().get("policy.string");
            for (String s : temp.split(";")) {
                String[] arr = s.split(":");
                xml.append("<allow-access-from domain=\"" + arr[0]
                        + "\" to-ports=\"" + arr[1] + "\" />");
            }
            xml.append("</cross-domain-policy>\0");
            CharBuffer tempChar =
                    CharBuffer.wrap(xml.toString().toCharArray());
            policyData = encoder.encode(tempChar);
        } catch (CharacterCodingException e) {
            CCommonHandler.writeErrLog(e);
        }
    }
}
